package com.hyb.hybmodulesfront.controller;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.hyb.hybmodulesfront.beans.vo.ActivityVo;
import com.hyb.hybmodulesfront.beans.vo.ModelAddress;
import com.ruoyi.common.core.constant.*;
import com.ruoyi.common.core.utils.*;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.system.api.*;
import com.ruoyi.system.api.domain.Leave;
import com.ruoyi.system.api.domain.Signin;
import com.ruoyi.system.api.domain.Signup;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;

@ConfigurationProperties(prefix = "spring")
@RestController
@RequestMapping("/activity")
public class ActivityController {

    @Autowired
    RedisTemplate<String,String> redisTemplate;


    @Autowired
    RedissonClient redissonClient;

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Autowired
    RemoteSignupRuleService remoteSignupRuleService;

    @Autowired
    RemoteActivityService remoteActivityService;

    @Autowired
    RemoteSigninService remoteSigninService;

    @Autowired
    RemoteSignupService remoteSignupService;

    @Autowired
    ThreadPoolTaskScheduler threadPoolTaskScheduler;

    @Autowired
    RemoteLeaveService remoteLeaveService;


    @Value("${spring.gp.ak}")
    private String ak;

    /*
    * 向活动请假
    * */

    @PostMapping("/approveLeave")
    public AjaxResult toApproveLeave(@RequestBody Leave leave){
        AjaxResult ajaxResult = remoteLeaveService.innerAdd(leave, SecurityConstants.INNER);
        if(ajaxResult.isError()){
            String data = (String) ajaxResult.get("msg");

            return AjaxResult.error(data);
        }
        return AjaxResult.success();
    }


    //到点请求redis返回该活动的编码
    @GetMapping("/getCode/{id}")
    public AjaxResult getCode(@PathVariable("id")String id){
        final HashOperations<String, String, String> hash = redisTemplate.opsForHash();

        if (!RegExUtil.isNumber(id)){
            return AjaxResult.error("id必须是数字");
        }
        String s = hash.get("activity::skill", id);
        if (StringUtils.isEmpty(s)){
            return AjaxResult.error("活动编码为空!");
        }
        ActivityVo activityVo = JSON.parseObject(s, ActivityVo.class);
        return AjaxResult.success().put("vo",activityVo);
    }


    //秒杀
    @PostMapping("/skill")
    public AjaxResult signup(@RequestParam("id")String id,@RequestParam("code")String code){
        final HashOperations<String, String, String> hash = redisTemplate.opsForHash();


        if (!RegExUtil.isNumber(id)){
            return AjaxResult.error("id必须是数字");
        }
        String s = hash.get("activity::skill", id);

        if (StringUtils.isEmpty(s)){
            return AjaxResult.error("活动编码为空!");
        }

        ActivityVo activityVo = JSON.parseObject(s, ActivityVo.class);
        if (!activityVo.getCheckCode().equals(code)){
            return AjaxResult.error("活动编码不正确!");
        }

        //是否报名过
        String signupKey=activityVo.getId()+"::isSkill";
        String isSign = hash.get(signupKey, String.valueOf(SecurityUtils.getUserId()));
        if (!StringUtils.isEmpty(isSign)){
            return AjaxResult.error("不能重复报名!");
        }
        //开始报名
        RSemaphore semaphore = redissonClient.getSemaphore("activity::skill::" + activityVo.getCheckCode());
        try {
            //尝试一百毫秒内拿取信号量,拿不到就放弃
            semaphore.tryAcquire(Constants.MILLISECOND, TimeUnit.MILLISECONDS);
            //设置报名表
            hash.put(signupKey,String.valueOf(SecurityUtils.getUserId()),"1");

            //发送mq消息,将报名信息插入到报名表里
            Signup signup = new Signup();
            signup.setActivityId(activityVo.getId());
            signup.setPf1(activityVo.getName());
            signup.setUserId(SecurityUtils.getUserId());
            signup.setPf2(SecurityUtils.getUsername());
            signup.setStatus(SignupConstants.CREATE_STATUS);
            signup.setCreateTime(DateUtils.getNowDate());
            signup.setUpdateTime(DateUtils.getNowDate());

            try{
                rabbitTemplate.convertAndSend("topicExchange","topic.activity.signup", signup);
            }catch (Exception e){
                //TODO 记录该消息在数据库里,然后开启定时任务扫描消息,继续发送
            }

            return AjaxResult.success("报名成功,请等待录取!");

        } catch (InterruptedException e) {
            return AjaxResult.error("网络错误,请稍后再试!");
        }
    }

    @GetMapping("/test")
    public AjaxResult test(HttpServletRequest request) throws Exception {


        return AjaxResult.success();
    }


    //签到
    @PostMapping("/signIn/code")
    public AjaxResult signIn(
            @RequestParam("id")String id,
            @RequestParam("code")String code,
            @RequestParam("type")Long type
    ,@RequestBody ModelAddress modelAddress){

        if (!RegExUtil.isNumber(id)){
            return AjaxResult.error("id必须是数字");
        }

        AjaxResult ajaxResult = remoteActivityService.checkInfo(Long.parseLong(id), SecurityConstants.INNER);
        if (ajaxResult.isError()){
            return AjaxResult.error("活动不存在,无法签到");
        }

        Object op = ajaxResult.get(ActivityConstant.NAME);
        ActivityVo o = JSONObject.parseObject(JSON.toJSONString(op), ActivityVo.class);

        if (!o.getStatus().equals(ActivityConstant.STARTING_STATUS)){
            return AjaxResult.error("该活动未开始,无法签到");
        }

        AjaxResult checkInfo = remoteSignupRuleService.getCheckInfo( id, type, SecurityConstants.INNER);
        if (checkInfo.isError()){
            return AjaxResult.error("该活动未存在该类型的签到规则,需负责人添加签到规则");
        }

        AjaxResult personalSignUp = remoteSignupService.getPersonalSignUp(id, SecurityConstants.INNER);
        if (personalSignUp.isError()){
            return AjaxResult.error("还没有报名!");
        }else{
            Object signUp = personalSignUp.get("signUp");
            Signup s = JSON.parseObject(JSON.toJSONString(signUp), Signup.class);
            if(!s.getStatus().equals(SigninConstants.SUCCESS)){
                return AjaxResult.error("您还未被录取,无法签到");
            }
        }

        //判断签到是否成功
        Object p = redisTemplate.opsForHash().get(SigninConstants.IS_SIGN + id, String.valueOf(SecurityUtils.getUserId()));
        if(p!=null){
            return AjaxResult.error("你已签到不能重复签到!");
        }

        //是哪个签到
        Signin signin = new Signin();
        if (type.equals(SigninConstants.PASSWORD_TYPE)){
            //验证密码
            String s = redisTemplate.opsForValue().get(SigninConstants.PASSWORD_RULE_KEY + id);
            if(StringUtils.isEmpty(s)){
                return AjaxResult.error("密码签到时间已过");
            }else{
                if(!SecurityUtils.matchesPassword(code,s)){
                    return AjaxResult.error("密码不匹配");
                }
            }
            signin.setPf1(String.valueOf(SigninConstants.PASSWORD_TYPE));
        }else{
            //就是二维码签到
            String s=redisTemplate.opsForValue().get(SigninConstants.QRCODE_RULE_KEY+id);
            if(StringUtils.isEmpty(s)){
                return AjaxResult.error("二维码签到时间已过");
            }
            if (!SecurityUtils.matchesPassword(code,s)){
                return AjaxResult.error("二维码密码不正确,请正确扫码");
            }
            signin.setPf1(String.valueOf(SigninConstants.QRCODE_TYPE));
        }

        //利用redis计算两地经纬度的距离
        GeoUtil.geoAdd(GeoConstants.from,modelAddress.getPointX(),modelAddress.getPointY());
        String position = o.getPosition();
        String[] strings = position.split(",");
        String[] split = strings[strings.length - 1].split("-");
        GeoUtil.geoAdd(GeoConstants.to,Double.parseDouble(split[0]),Double.parseDouble(split[1]));
        long v = GeoUtil.distanceBetween(GeoConstants.to, GeoConstants.from);
        String s = redisTemplate.opsForValue().get(SigninConstants.POSITION_LONG + id);
        if(StringUtils.isEmpty(s)){
            return AjaxResult.error("签到时间已过");
        }
        if (v>Long.parseLong(s)){
            return AjaxResult.error("范围超出,无法签到,请在允许的范围内签到!");
        }
        signin.setActivityId(o.getId());
        signin.setActivityName(o.getName());
        signin.setStatus(SigninConstants.SUCCESS);
        signin.setUserId(SecurityUtils.getUserId());
        signin.setUserName(SecurityUtils.getUsername());
        signin.setUpdateTime(DateUtils.getNowDate());
        signin.setPosition(modelAddress.getAddress());
        signin.setPositionX(String.valueOf(modelAddress.getPointX()));
        signin.setPositionY(String.valueOf(modelAddress.getPointY()));
        //远程调用服务插入到签到表中
        rabbitTemplate.convertAndSend("topicExchange","topic.sign.sign",signin);

        redisTemplate.opsForHash().put(SigninConstants.IS_SIGN+id,String.valueOf(SecurityUtils.getUserId()),"1");

        //活动结束后,删除redis的签到信息
        threadPoolTaskScheduler.schedule(new Runnable() {
            @Override
            public void run() {
                redisTemplate.delete(SigninConstants.IS_SIGN+id);
            }
        },o.getLastTime());

        return AjaxResult.success().put("msg","签到成功");

    }


}
